home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / mig / dist / server.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-01-28  |  44.6 KB  |  1,603 lines

  1. /* 
  2.  * Mach Operating System
  3.  * Copyright (c) 1991,1990 Carnegie Mellon University
  4.  * All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify and distribute this software and its
  7.  * documentation is hereby granted, provided that both the copyright
  8.  * notice and this permission notice appear in all copies of the
  9.  * software, derivative works or modified versions, and any portions
  10.  * thereof, and that both notices appear in supporting documentation.
  11.  * 
  12.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  13.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  14.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  15.  * 
  16.  * Carnegie Mellon requests users of this software to return to
  17.  * 
  18.  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
  19.  *  School of Computer Science
  20.  *  Carnegie Mellon University
  21.  *  Pittsburgh PA 15213-3890
  22.  * 
  23.  * any improvements or extensions that they make and grant Carnegie Mellon
  24.  * the rights to redistribute these changes.
  25.  */
  26. /*
  27.  * HISTORY
  28.  * $Log:    server.c,v $
  29.  * Revision 2.8  92/01/14  16:46:39  rpd
  30.  *     Modified WriteInitializeCount, WriteExtractArg
  31.  *     for the revised CountInOut implementation.
  32.  *     Fixed Indefinite code generation, to allow short type descriptors.
  33.  *     Added deallocate bit handling to Indefinite code generation.
  34.  *     [92/01/08            rpd]
  35.  * 
  36.  * Revision 2.7  92/01/03  20:30:09  dbg
  37.  *     Generate <subsystem>_server_routine to return unpacking function
  38.  *     pointer.
  39.  *     [91/11/11            dbg]
  40.  * 
  41.  *     For inline variable-length arrays that are Out parameters, allow
  42.  *     passing the user's count argument to the server as an InOut
  43.  *     parameter.
  44.  *     [91/11/11            dbg]
  45.  * 
  46.  *     Redo handling of OUT arrays that are passed in-line or
  47.  *     out-of-line.  Treat more like out-of-line arrays:
  48.  *     user allocates buffer and pointer
  49.  *     fills in pointer with buffer address
  50.  *     passes pointer to stub
  51.  *     stub copies data to *pointer, or changes pointer
  52.  *     User can always use *pointer.
  53.  * 
  54.  *     Change argByReferenceUser to a field in argument_t.
  55.  *     [91/09/04            dbg]
  56.  * 
  57.  * Revision 2.6  91/08/28  11:17:21  jsb
  58.  *     Replaced ServerProcName with ServerDemux.
  59.  *     [91/08/13            rpd]
  60.  * 
  61.  *     Removed Camelot and TrapRoutine support.
  62.  *     Changed MsgKind to MsgSeqno.
  63.  *     [91/08/12            rpd]
  64.  * 
  65.  * Revision 2.5  91/07/31  18:10:51  dbg
  66.  *     Allow indefinite-length variable arrays.  They may be copied
  67.  *     either in-line or out-of-line, depending on size.
  68.  * 
  69.  *     Copy variable-length C Strings with mig_strncpy, to combine
  70.  *     'strcpy' and 'strlen' operations.
  71.  * 
  72.  *     New method for advancing request message pointer past
  73.  *     variable-length arguments.  We no longer have to know the order
  74.  *     of variable-length arguments and their count arguments.
  75.  * 
  76.  *     Remove redundant assignments (to msgh_simple, msgh_size) in
  77.  *     generated code.
  78.  *     [91/07/17            dbg]
  79.  * 
  80.  * Revision 2.4  91/06/25  10:31:51  rpd
  81.  *     Cast request and reply ports to ipc_port_t in KernelServer stubs.
  82.  *     [91/05/27            rpd]
  83.  * 
  84.  * Revision 2.3  91/02/05  17:55:37  mrt
  85.  *     Changed to new Mach copyright
  86.  *     [91/02/01  17:55:30  mrt]
  87.  * 
  88.  * Revision 2.2  90/06/02  15:05:29  rpd
  89.  *     Created for new IPC.
  90.  *     [90/03/26  21:13:12  rpd]
  91.  * 
  92.  * 07-Apr-89  Richard Draves (rpd) at Carnegie-Mellon University
  93.  *    Extensive revamping.  Added polymorphic arguments.
  94.  *    Allow multiple variable-sized inline arguments in messages.
  95.  *
  96.  * 18-Oct-88  Mary Thompson (mrt) at Carnegie-Mellon University
  97.  *    Set the local port in the server reply message to
  98.  *    MACH_PORT_NULL for greater efficiency and to make Camelot
  99.  *    happy.
  100.  *
  101.  * 18-Apr-88  Mary Thompson (mrt) at Carnegie-Mellon University
  102.  *    Changed call to WriteLocalVarDecl in WriteMsgVarDecl
  103.  *    to write out the parameters for the C++ code to a call
  104.  *    a new routine WriteServerVarDecl which includes the *
  105.  *    for reference variable, but uses the transType if it
  106.  *    exists.
  107.  *
  108.  * 27-Feb-88  Richard Draves (rpd) at Carnegie-Mellon University
  109.  *    Changed reply message initialization for camelot interfaces.
  110.  *    Now we assume camelot interfaces are all camelotroutines and
  111.  *    always initialize the dummy field & tid field.  This fixes
  112.  *    the wrapper-server-call bug in distributed transactions.
  113.  *
  114.  * 23-Feb-88  Mary Thompson (mrt) at Carnegie-Mellon University
  115.  *    Changed the include of camelot_types.h to cam/camelot_types.h
  116.  *
  117.  * 19-Feb-88  Mary Thompson (mrt) at Carnegie-Mellon University
  118.  *    Fixed WriteDestroyArg to not call the destructor
  119.  *    function on any in/out args.
  120.  *
  121.  *  4-Feb-88  Mary Thompson (mrt) at Carnegie-Mellon University
  122.  *    Fixed dld's code to write out parameter list to
  123.  *    use WriteLocalVarDecl to get transType or ServType if
  124.  *    they exist.
  125.  *
  126.  * 19-Jan-88  David Golub (dbg) at Carnegie-Mellon University
  127.  *    Change variable-length inline array declarations to use
  128.  *    maximum size specified to Mig.  Make message variable
  129.  *    length if the last item in the message is variable-length
  130.  *    and inline.  Use argMultipler field to convert between
  131.  *    argument and IPC element counts.
  132.  *
  133.  * 18-Jan-88  David Detlefs (dld) at Carnegie-Mellon University
  134.  *    Modified to produce C++ compatible code via #ifdefs.
  135.  *    All changes have to do with argument declarations.
  136.  *
  137.  *  2-Dec-87  David Golub (dbg) at Carnegie-Mellon University
  138.  *    Added destructor function for IN arguments to server.
  139.  *
  140.  * 18-Nov-87  Jeffrey Eppinger (jle) at Carnegie-Mellon University
  141.  *    Changed to typedef "novalue" as "void" if we're using hc.
  142.  *
  143.  * 17-Sep-87  Bennet Yee (bsy) at Carnegie-Mellon University
  144.  *    Added _<system>SymTab{Base|End} for use with security
  145.  *    dispatch routine.  It is neccessary for the authorization
  146.  *    system to know the operations by symbolic names.
  147.  *    It is harmless to user code as it only means an extra
  148.  *    array if it is accidentally turned on.
  149.  *
  150.  * 24-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  151.  *    Corrected the setting of retcode for CamelotRoutines.
  152.  *
  153.  * 21-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  154.  *    Added deallocflag to call to WritePackArgType.
  155.  *
  156.  * 14-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  157.  *    Moved type declarations and assignments for DummyType 
  158.  *    and tidType to server demux routine. Automatically
  159.  *    include camelot_types.h and msg_types.h for interfaces 
  160.  *    containing camelotRoutines.
  161.  *
  162.  *  8-Jun-87  Mary Thompson (mrt) at Carnegie-Mellon University
  163.  *    Removed #include of sys/types.h and strings.h from WriteIncludes.
  164.  *    Changed the KERNEL include from ../h to sys/
  165.  *    Removed extern from WriteServer to make hi-c happy
  166.  *
  167.  * 28-May-87  Richard Draves (rpd) at Carnegie-Mellon University
  168.  *    Created.
  169.  */
  170.  
  171. #include <assert.h>
  172.  
  173. #include <mach/message.h>
  174. #include "write.h"
  175. #include "utils.h"
  176. #include "global.h"
  177.  
  178. static void
  179. WriteIncludes(file)
  180.     FILE *file;
  181. {
  182.     fprintf(file, "#define EXPORT_BOOLEAN\n");
  183.     fprintf(file, "#include <mach/boolean.h>\n");
  184.     fprintf(file, "#include <mach/kern_return.h>\n");
  185.     fprintf(file, "#include <mach/message.h>\n");
  186.     fprintf(file, "#include <mach/mig_errors.h>\n");
  187.     if (IsKernelServer)
  188.     fprintf(file, "#include <ipc/ipc_port.h>\n");
  189.     fprintf(file, "\n");
  190. }
  191.  
  192. static void
  193. WriteGlobalDecls(file)
  194.     FILE *file;
  195. {
  196.     fprintf(file, "/* Due to pcc compiler bug, cannot use void */\n");
  197.     fprintf(file, "#if\t%s || defined(hc)\n", NewCDecl);
  198.     fprintf(file, "#define novalue void\n");
  199.     fprintf(file, "#else\n");
  200.     fprintf(file, "#define novalue int\n");
  201.     fprintf(file, "#endif\n");
  202.     fprintf(file, "\n");
  203.  
  204.     if (RCSId != strNULL)
  205.     WriteRCSDecl(file, strconcat(SubsystemName, "_server"), RCSId);
  206.  
  207.     /* Used for locations in the request message, *not* reply message.
  208.        Reply message locations aren't dependent on IsKernelServer. */
  209.  
  210.     if (IsKernelServer)
  211.     {
  212.     fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n");
  213.     fprintf(file, "#define MACH_MSGH_BITS_REQUEST(bits)");
  214.     fprintf(file, "\tMACH_MSGH_BITS_REMOTE(bits)\n");
  215.     fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n");
  216.     fprintf(file, "#define MACH_MSGH_BITS_REPLY(bits)");
  217.     fprintf(file, "\tMACH_MSGH_BITS_LOCAL(bits)\n");
  218.     }
  219.     else
  220.     {
  221.     fprintf(file, "#define msgh_request_port\tmsgh_local_port\n");
  222.     fprintf(file, "#define MACH_MSGH_BITS_REQUEST(bits)");
  223.     fprintf(file, "\tMACH_MSGH_BITS_LOCAL(bits)\n");
  224.     fprintf(file, "#define msgh_reply_port\t\tmsgh_remote_port\n");
  225.     fprintf(file, "#define MACH_MSGH_BITS_REPLY(bits)");
  226.     fprintf(file, "\tMACH_MSGH_BITS_REMOTE(bits)\n");
  227.     }
  228.     fprintf(file, "\n");
  229. }
  230.  
  231. static void
  232. WriteProlog(file)
  233.     FILE *file;
  234. {
  235.     fprintf(file, "/* Module %s */\n", SubsystemName);
  236.     fprintf(file, "\n");
  237.     
  238.     WriteIncludes(file);
  239.     WriteBogusDefines(file);
  240.     WriteGlobalDecls(file);
  241. }
  242.  
  243.  
  244. static void
  245. WriteSymTabEntries(file, stats)
  246.     FILE *file;
  247.     statement_t *stats;
  248. {
  249.     register statement_t *stat;
  250.     register u_int current = 0;
  251.  
  252.     for (stat = stats; stat != stNULL; stat = stat->stNext)
  253.     if (stat->stKind == skRoutine) {
  254.         register    num = stat->stRoutine->rtNumber;
  255.         char    *name = stat->stRoutine->rtName;
  256.         while (++current <= num)
  257.         fprintf(file,"\t\t\t{ \"\", 0, 0 },\n");
  258.         fprintf(file, "\t{ \"%s\", %d, _X%s },\n",
  259.             name,
  260.         SubsystemBase + current - 1,
  261.         name);
  262.     }
  263.     while (++current <= rtNumber)
  264.     fprintf(file,"\t{ \"\", 0, 0 },\n");
  265. }
  266.  
  267. static void
  268. WriteArrayEntries(file, stats)
  269.     FILE *file;
  270.     statement_t *stats;
  271. {
  272.     register u_int current = 0;
  273.     register statement_t *stat;
  274.  
  275.     for (stat = stats; stat != stNULL; stat = stat->stNext)
  276.     if (stat->stKind == skRoutine)
  277.     {
  278.         register routine_t *rt = stat->stRoutine;
  279.  
  280.         while (current++ < rt->rtNumber)
  281.         fprintf(file, "\t\t0,\n");
  282.         fprintf(file, "\t\t_X%s,\n", rt->rtName);
  283.     }
  284.     while (current++ < rtNumber)
  285.     fprintf(file, "\t\t\t0,\n");
  286. }
  287.  
  288. static void
  289. WriteEpilog(file, stats)
  290.     FILE *file;
  291.     statement_t *stats;
  292. {
  293.     fprintf(file, "\n");
  294.  
  295.     /*
  296.      * First, the symbol table
  297.      */
  298.      fprintf(file, "static mig_routine_t %s_routines[] = {\n", ServerDemux);
  299.  
  300.      WriteArrayEntries(file, stats);
  301.  
  302.      fprintf(file, "};\n");
  303.      fprintf(file, "\n");
  304.  
  305.      /*
  306.       * Then, the server routine
  307.       */
  308.     fprintf(file, "mig_external boolean_t %s\n", ServerDemux);
  309.     fprintf(file, "#if\t%s\n", NewCDecl);
  310.     fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
  311.     fprintf(file, "#else\n");
  312.     fprintf(file, "\t(InHeadP, OutHeadP)\n");
  313.     fprintf(file, "\tmach_msg_header_t *InHeadP, *OutHeadP;\n");
  314.     fprintf(file, "#endif\n");
  315.  
  316.     fprintf(file, "{\n");
  317.     fprintf(file, "\tregister mach_msg_header_t *InP =  InHeadP;\n");
  318.  
  319.     fprintf(file, "\tregister mig_reply_header_t *OutP = (mig_reply_header_t *) OutHeadP;\n");
  320.  
  321.     fprintf(file, "\n");
  322.  
  323.     WriteStaticDecl(file, itRetCodeType,
  324.             itRetCodeType->itDeallocate, itRetCodeType->itLongForm,
  325.             !IsKernelServer, "RetCodeType");
  326.     fprintf(file, "\n");
  327.  
  328.     fprintf(file, "\tregister mig_routine_t routine;\n");
  329.     fprintf(file, "\n");
  330.  
  331.     fprintf(file, "\tOutP->Head.msgh_bits = ");
  332.     fprintf(file, "MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InP->msgh_bits), 0);\n");
  333.     fprintf(file, "\tOutP->Head.msgh_size = sizeof *OutP;\n");
  334.     fprintf(file, "\tOutP->Head.msgh_remote_port = InP->msgh_reply_port;\n");
  335.     fprintf(file, "\tOutP->Head.msgh_local_port = MACH_PORT_NULL;\n");
  336.     fprintf(file, "\tOutP->Head.msgh_seqno = 0;\n");
  337.     fprintf(file, "\tOutP->Head.msgh_id = InP->msgh_id + 100;\n");
  338.     fprintf(file, "\n");
  339.     WritePackMsgType(file, itRetCodeType,
  340.              itRetCodeType->itDeallocate, itRetCodeType->itLongForm,
  341.              !IsKernelServer, "OutP->RetCodeType", "RetCodeType");
  342.     fprintf(file, "\n");
  343.  
  344.     fprintf(file, "\tif ((InP->msgh_id > %d) || (InP->msgh_id < %d) ||\n",
  345.         SubsystemBase + rtNumber - 1, SubsystemBase);
  346.     fprintf(file, "\t    ((routine = %s_routines[InP->msgh_id - %d]) == 0)) {\n",
  347.         ServerDemux, SubsystemBase);
  348.     fprintf(file, "\t\tOutP->RetCode = MIG_BAD_ID;\n");
  349.     fprintf(file, "\t\treturn FALSE;\n");
  350.     fprintf(file, "\t}\n");
  351.  
  352.     /* Call appropriate routine */
  353.     fprintf(file, "\t(*routine) (InP, &OutP->Head);\n");
  354.     fprintf(file, "\treturn TRUE;\n");
  355.     fprintf(file, "}\n");
  356.     fprintf(file, "\n");
  357.  
  358.     /*
  359.      * Then, the <subsystem>_server_routine routine
  360.      */
  361.     fprintf(file, "mig_external mig_routine_t %s_routine\n", ServerDemux);
  362.     fprintf(file, "#if\t%s\n", NewCDecl);
  363.     fprintf(file, "\t(mach_msg_header_t *InHeadP)\n");
  364.     fprintf(file, "#else\n");
  365.     fprintf(file, "\t(InHeadP)\n");
  366.     fprintf(file, "\tmach_msg_header_t *InHeadP;\n");
  367.     fprintf(file, "#endif\n");
  368.  
  369.     fprintf(file, "{\n");
  370.     fprintf(file, "\tregister int msgh_id;\n");
  371.     fprintf(file, "\n");
  372.     fprintf(file, "\tmsgh_id = InHeadP->msgh_id - %d;\n", SubsystemBase);
  373.     fprintf(file, "\n");
  374.     fprintf(file, "\tif ((msgh_id > %d) || (msgh_id < 0))\n",
  375.         rtNumber - 1);
  376.     fprintf(file, "\t\treturn 0;\n");
  377.     fprintf(file, "\n");
  378.     fprintf(file, "\treturn %s_routines[msgh_id];\n", ServerDemux);
  379.     fprintf(file, "}\n");
  380.     fprintf(file, "\n");
  381.  
  382.     /* symtab */
  383.  
  384.     if (GenSymTab) {
  385.     fprintf(file,"\nmig_symtab_t _%sSymTab[] = {\n",SubsystemName);
  386.     WriteSymTabEntries(file,stats);
  387.     fprintf(file,"};\n");
  388.     fprintf(file,"int _%sSymTabBase = %d;\n",SubsystemName,SubsystemBase);
  389.     fprintf(file,"int _%sSymTabEnd = %d;\n",SubsystemName,SubsystemBase+rtNumber);
  390.     }
  391. }
  392.  
  393. /*
  394.  *  Returns the return type of the server-side work function.
  395.  *  Suitable for "extern %s serverfunc()".
  396.  */
  397. static char *
  398. ServerSideType(rt)
  399.     routine_t *rt;
  400. {
  401.     if (rt->rtServerReturn == argNULL)
  402.     return "void";
  403.     else
  404.     return rt->rtServerReturn->argType->itTransType;
  405. }
  406.  
  407. static void
  408. WriteLocalVarDecl(file, arg)
  409.     FILE *file;
  410.     register argument_t *arg;
  411. {
  412.     register ipc_type_t *it = arg->argType;
  413.  
  414.     if (it->itInLine && it->itVarArray)
  415.     {
  416.     register ipc_type_t *btype = it->itElement;
  417.  
  418.     fprintf(file, "\t%s %s[%d]", btype->itTransType,
  419.         arg->argVarName, it->itNumber/btype->itNumber);
  420.     }
  421.     else
  422.     fprintf(file, "\t%s %s", it->itTransType, arg->argVarName);
  423. }
  424.  
  425. static void
  426. WriteLocalPtrDecl(file, arg)
  427.     FILE *file;
  428.     register argument_t *arg;
  429. {
  430.     fprintf(file, "\t%s *%sP",
  431.         FetchServerType(arg->argType->itElement),
  432.         arg->argVarName);
  433. }
  434.  
  435. static void
  436. WriteServerArgDecl(file, arg)
  437.     FILE *file;
  438.     argument_t *arg;
  439. {
  440.     fprintf(file, "%s %s%s",
  441.         arg->argType->itTransType,
  442.         arg->argByReferenceServer ? "*" : "",
  443.         arg->argVarName);
  444. }
  445.  
  446. /*
  447.  *  Writes the local variable declarations which are always
  448.  *  present:  InP, OutP, the server-side work function.
  449.  */
  450. static void
  451. WriteVarDecls(file, rt)
  452.     FILE *file;
  453.     routine_t *rt;
  454. {
  455.     int i;
  456.     boolean_t NeedMsghSize = FALSE;
  457.     boolean_t NeedMsghSizeDelta = FALSE;
  458.  
  459.     fprintf(file, "\tregister Request *In0P = (Request *) InHeadP;\n");
  460.     for (i = 1; i <= rt->rtMaxRequestPos; i++)
  461.     fprintf(file, "\tregister Request *In%dP;\n", i);
  462.     fprintf(file, "\tregister Reply *OutP = (Reply *) OutHeadP;\n");
  463.  
  464.     fprintf(file, "\tmig_external %s %s\n",
  465.         ServerSideType(rt), rt->rtServerName);
  466.     fprintf(file, "#if\t%s\n", NewCDecl);
  467.     fprintf(file, "\t\t(");
  468.     WriteList(file, rt->rtArgs, WriteServerArgDecl, akbServerArg, ", ", "");
  469.     fprintf(file, ");\n");
  470.     fprintf(file, "#else\n");
  471.     fprintf(file, "\t\t();\n");
  472.     fprintf(file, "#endif\n");
  473.     fprintf(file, "\n");
  474.  
  475.     if (!rt->rtSimpleFixedReply)
  476.     fprintf(file, "\tboolean_t msgh_simple;\n");
  477.     else if (!rt->rtSimpleCheckRequest)
  478.     {
  479.     fprintf(file, "#if\tTypeCheck\n");
  480.     fprintf(file, "\tboolean_t msgh_simple;\n");
  481.     fprintf(file, "#endif\tTypeCheck\n");
  482.     fprintf(file, "\n");
  483.     }
  484.  
  485.     /* if either request or reply is variable, we may need
  486.        msgh_size_delta and msgh_size */
  487.  
  488.     if (rt->rtNumRequestVar > 0)
  489.     NeedMsghSize = TRUE;
  490.     if (rt->rtMaxRequestPos > 0)
  491.     NeedMsghSizeDelta = TRUE;
  492.  
  493.     if (rt->rtNumReplyVar > 1)
  494.     NeedMsghSize = TRUE;
  495.     if (rt->rtMaxReplyPos > 0)
  496.     NeedMsghSizeDelta = TRUE;
  497.  
  498.     if (NeedMsghSize)
  499.     fprintf(file, "\tunsigned int msgh_size;\n");
  500.     if (NeedMsghSizeDelta)
  501.     fprintf(file, "\tunsigned int msgh_size_delta;\n");
  502.  
  503.     if (NeedMsghSize || NeedMsghSizeDelta)
  504.     fprintf(file, "\n");
  505. }
  506.  
  507. static void
  508. WriteMsgError(file, error)
  509.     FILE *file;
  510.     char *error;
  511. {
  512.     fprintf(file, "\t\t{ OutP->RetCode = %s; return; }\n", error);
  513. }
  514.  
  515. static void
  516. WriteReplyInit(file, rt)
  517.     FILE *file;
  518.     routine_t *rt;
  519. {
  520.     boolean_t printed_nl = FALSE;
  521.  
  522.     if (rt->rtSimpleFixedReply)
  523.     {
  524.     if (!rt->rtSimpleSendReply) /* complex reply message */
  525.     {
  526.         printed_nl = TRUE;
  527.         fprintf(file, "\n");
  528.         fprintf(file,
  529.         "\tOutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n");
  530.     }
  531.     }
  532.     else
  533.     {
  534.     printed_nl = TRUE;
  535.     fprintf(file, "\n");
  536.     fprintf(file, "\tmsgh_simple = %s;\n", 
  537.               strbool(rt->rtSimpleSendReply));
  538.     }
  539.  
  540.     if (rt->rtNumReplyVar == 0)
  541.     {
  542.     if (!printed_nl)
  543.         fprintf(file, "\n");
  544.     fprintf(file, "\tOutP->Head.msgh_size = %d;\n", rt->rtReplySize);
  545.     }
  546. }
  547.  
  548. static void
  549. WriteReplyHead(file, rt)
  550.     FILE *file;
  551.     routine_t *rt;
  552. {
  553.     if ((!rt->rtSimpleFixedReply) ||
  554.     (rt->rtNumReplyVar > 1))
  555.     {
  556.     fprintf(file, "\n");
  557.     if (rt->rtMaxReplyPos > 0)
  558.         fprintf(file, "\tOutP = (Reply *) OutHeadP;\n");
  559.     }
  560.  
  561.     if (!rt->rtSimpleFixedReply)
  562.     {
  563.     fprintf(file, "\tif (!msgh_simple)\n");
  564.     fprintf(file,
  565.         "\t\tOutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n");
  566.     }
  567.     if (rt->rtNumReplyVar > 1)
  568.     fprintf(file, "\tOutP->Head.msgh_size = msgh_size;\n");
  569. }
  570.  
  571. static void
  572. WriteCheckHead(file, rt)
  573.     FILE *file;
  574.     routine_t *rt;
  575. {
  576.     fprintf(file, "#if\tTypeCheck\n");
  577.     if (rt->rtNumRequestVar > 0)
  578.     fprintf(file, "\tmsgh_size = In0P->Head.msgh_size;\n");
  579.     if (!rt->rtSimpleCheckRequest)
  580.     fprintf(file, "\tmsgh_simple = !(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);\n");
  581.  
  582.     if (rt->rtNumRequestVar > 0)
  583.     fprintf(file, "\tif ((msgh_size < %d)",
  584.         rt->rtRequestSize);
  585.     else
  586.     fprintf(file, "\tif ((In0P->Head.msgh_size != %d)",
  587.         rt->rtRequestSize);
  588.  
  589.     if (rt->rtSimpleCheckRequest)
  590.     fprintf(file, " ||\n\t    %s(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)",
  591.         rt->rtSimpleReceiveRequest ? "" : "!");
  592.     fprintf(file, ")\n");
  593.     WriteMsgError(file, "MIG_BAD_ARGUMENTS");
  594.     fprintf(file, "#endif\tTypeCheck\n");
  595.     fprintf(file, "\n");
  596. }
  597.  
  598. static void
  599. WriteTypeCheck(file, arg)
  600.     FILE *file;
  601.     register argument_t *arg;
  602. {
  603.     register ipc_type_t *it = arg->argType;
  604.     register routine_t *rt = arg->argRoutine;
  605.  
  606.     fprintf(file, "#if\tTypeCheck\n");
  607.     if (akCheck(arg->argKind, akbRequestQC))
  608.     {
  609.     fprintf(file, "#if\tUseStaticMsgType\n");
  610.     fprintf(file, "\tif (* (int *) &In%dP->%s != * (int *) &%sCheck)\n",
  611.         arg->argRequestPos, arg->argTTName, arg->argVarName);
  612.     fprintf(file, "#else\tUseStaticMsgType\n");
  613.     }
  614.     fprintf(file, "\tif (");
  615.     if (!it->itIndefinite) {
  616.     fprintf(file, "(In%dP->%s%s.msgt_inline != %s) ||\n\t    ",
  617.         arg->argRequestPos, arg->argTTName,
  618.         arg->argLongForm ? ".msgtl_header" : "",
  619.         strbool(it->itInLine));
  620.     }
  621.     fprintf(file, "(In%dP->%s%s.msgt_longform != %s) ||\n",
  622.         arg->argRequestPos, arg->argTTName,
  623.         arg->argLongForm ? ".msgtl_header" : "",
  624.         strbool(arg->argLongForm));
  625.     if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
  626.     {
  627.     if (!rt->rtSimpleCheckRequest)
  628.         fprintf(file, "\t    (MACH_MSG_TYPE_PORT_ANY(In%dP->%s.msgt%s_name) && msgh_simple) ||\n",
  629.             arg->argRequestPos, arg->argTTName,
  630.             arg->argLongForm ? "l" : "");
  631.     }
  632.     else
  633.     fprintf(file, "\t    (In%dP->%s.msgt%s_name != %s) ||\n",
  634.         arg->argRequestPos, arg->argTTName,
  635.         arg->argLongForm ? "l" : "",
  636.         it->itOutNameStr);
  637.     if (!it->itVarArray)
  638.     fprintf(file, "\t    (In%dP->%s.msgt%s_number != %d) ||\n",
  639.         arg->argRequestPos, arg->argTTName,
  640.         arg->argLongForm ? "l" : "",
  641.         it->itNumber);
  642.     fprintf(file, "\t    (In%dP->%s.msgt%s_size != %d))\n",
  643.         arg->argRequestPos, arg->argTTName,
  644.         arg->argLongForm ? "l" : "",
  645.         it->itSize);
  646.     if (akCheck(arg->argKind, akbRequestQC))
  647.     fprintf(file, "#endif\tUseStaticMsgType\n");
  648.     WriteMsgError(file, "MIG_BAD_ARGUMENTS");
  649.     fprintf(file, "#endif\tTypeCheck\n");
  650.     fprintf(file, "\n");
  651. }
  652.  
  653. static void
  654. WriteCheckArgSize(file, arg)
  655.     FILE *file;
  656.     register argument_t *arg;
  657. {
  658.     register ipc_type_t *ptype = arg->argType;
  659.     register ipc_type_t *btype = ptype->itElement;
  660.     argument_t *count = arg->argCount;
  661.     int multiplier = btype->itTypeSize / btype->itNumber;
  662.  
  663.     if (ptype->itIndefinite) {
  664.     /*
  665.      * Check descriptor.  If out-of-line, use standard size.
  666.      */
  667.     fprintf(file, "(In%dP->%s%s.msgt_inline) ? ",
  668.         arg->argRequestPos,
  669.         arg->argTTName,
  670.         arg->argLongForm ? ".msgtl_header" : "");
  671.     }
  672.  
  673.     if (multiplier > 1)
  674.     fprintf(file, "%d * ", multiplier);
  675.  
  676.     fprintf(file, "In%dP->%s", arg->argRequestPos, count->argMsgField);
  677.  
  678.     /* If the base type size of the data field isn`t a multiple of 4,
  679.        we have to round up. */
  680.     if (btype->itTypeSize % 4 != 0)
  681.     fprintf(file, " + 3 & ~3");
  682.  
  683.     if (ptype->itIndefinite) {
  684.     fprintf(file, " : sizeof(%s *)", FetchServerType(btype));
  685.     }
  686. }
  687.  
  688. static void
  689. WriteCheckMsgSize(file, arg)
  690.     FILE *file;
  691.     register argument_t *arg;
  692. {
  693.     register routine_t *rt = arg->argRoutine;
  694.  
  695.     /* If there aren't any more In args after this, then
  696.        we can use the msgh_size_delta value directly in
  697.        the TypeCheck conditional. */
  698.  
  699.     if (arg->argRequestPos == rt->rtMaxRequestPos)
  700.     {
  701.     fprintf(file, "#if\tTypeCheck\n");
  702.     fprintf(file, "\tif (msgh_size != %d + (",
  703.         rt->rtRequestSize);
  704.     WriteCheckArgSize(file, arg);
  705.     fprintf(file, "))\n");
  706.  
  707.     WriteMsgError(file, "MIG_BAD_ARGUMENTS");
  708.     fprintf(file, "#endif\tTypeCheck\n");
  709.     }
  710.     else
  711.     {
  712.     /* If there aren't any more variable-sized arguments after this,
  713.        then we must check for exact msg-size and we don't need to
  714.        update msgh_size. */
  715.  
  716.     boolean_t LastVarArg = arg->argRequestPos+1 == rt->rtNumRequestVar;
  717.  
  718.     /* calculate the actual size in bytes of the data field.  note
  719.        that this quantity must be a multiple of four.  hence, if
  720.        the base type size isn't a multiple of four, we have to
  721.        round up.  note also that btype->itNumber must
  722.        divide btype->itTypeSize (see itCalculateSizeInfo). */
  723.  
  724.     fprintf(file, "\tmsgh_size_delta = ");
  725.     WriteCheckArgSize(file, arg);
  726.     fprintf(file, ";\n");
  727.     fprintf(file, "#if\tTypeCheck\n");
  728.  
  729.     /* Don't decrement msgh_size until we've checked that
  730.        it won't underflow. */
  731.  
  732.     if (LastVarArg)
  733.         fprintf(file, "\tif (msgh_size != %d + msgh_size_delta)\n",
  734.         rt->rtRequestSize);
  735.     else
  736.         fprintf(file, "\tif (msgh_size < %d + msgh_size_delta)\n",
  737.         rt->rtRequestSize);
  738.     WriteMsgError(file, "MIG_BAD_ARGUMENTS");
  739.  
  740.     if (!LastVarArg)
  741.         fprintf(file, "\tmsgh_size -= msgh_size_delta;\n");
  742.  
  743.     fprintf(file, "#endif\tTypeCheck\n");
  744.     }
  745.     fprintf(file, "\n");
  746. }
  747.  
  748. static char *
  749. InArgMsgField(arg)
  750.     register argument_t *arg;
  751. {
  752.     static char buffer[100];
  753.  
  754.     /*
  755.      *    Inside the kernel, the request and reply port fields
  756.      *    really hold ipc_port_t values, not mach_port_t values.
  757.      *    Hence we must cast the values.
  758.      */
  759.  
  760.     if (IsKernelServer &&
  761.     ((akIdent(arg->argKind) == akeRequestPort) ||
  762.      (akIdent(arg->argKind) == akeReplyPort)))
  763.     sprintf(buffer, "(ipc_port_t) In%dP->%s",
  764.         arg->argRequestPos, arg->argMsgField);
  765.     else
  766.     sprintf(buffer, "In%dP->%s",
  767.         arg->argRequestPos, arg->argMsgField);
  768.  
  769.     return buffer;
  770. }
  771.  
  772. static void
  773. WriteExtractArgValue(file, arg)
  774.     FILE *file;
  775.     register argument_t *arg;
  776. {
  777.     register ipc_type_t *it = arg->argType;
  778.  
  779.     if (arg->argMultiplier > 1)
  780.     WriteCopyType(file, it, "%s", "/* %s */ %s / %d",
  781.               arg->argVarName, InArgMsgField(arg), arg->argMultiplier);
  782.     else if (it->itInTrans != strNULL)
  783.     WriteCopyType(file, it, "%s", "/* %s */ %s(%s)",
  784.               arg->argVarName, it->itInTrans, InArgMsgField(arg));
  785.     else
  786.     WriteCopyType(file, it, "%s", "/* %s */ %s",
  787.               arg->argVarName, InArgMsgField(arg));
  788.     fprintf(file, "\n");
  789. }
  790.  
  791. static void
  792. WriteInitializeCount(file, arg)
  793.     FILE *file;
  794.     register argument_t *arg;
  795. {
  796.     register ipc_type_t *ptype = arg->argParent->argType;
  797.     register ipc_type_t *btype = ptype->itElement;
  798.  
  799.     /*
  800.      *    Initialize 'count' argument for variable-length inline OUT parameter
  801.      *    with maximum allowed number of elements.
  802.      */
  803.  
  804.     fprintf(file, "\t%s = %d;\n", arg->argVarName,
  805.         ptype->itNumber/btype->itNumber);
  806.  
  807.     /*
  808.      *    If the user passed in a count, then we use the minimum.
  809.      *    We can't let the user completely override our maximum,
  810.      *    or the user might convince the server to overwrite the buffer.
  811.      */
  812.  
  813.     if (arg->argCInOut != argNULL) {
  814.     char *msgfield = InArgMsgField(arg->argCInOut);
  815.  
  816.     fprintf(file, "\tif (%s < %s)\n", msgfield, arg->argVarName);
  817.     fprintf(file, "\t\t%s = %s;\n", arg->argVarName, msgfield);
  818.     }
  819.  
  820.     fprintf(file, "\n");
  821. }
  822.  
  823. static void
  824. WriteInitializePtr(file, arg)
  825.     FILE *file;
  826.     register argument_t *arg;
  827. {
  828.     if (akCheck(arg->argKind, akbVarNeeded))
  829.     fprintf(file, "\t%sP = %s;\n",
  830.         arg->argVarName, arg->argVarName);
  831.     else
  832.     fprintf(file, "\t%sP = OutP->%s;\n",
  833.         arg->argVarName, arg->argMsgField);
  834. }
  835.  
  836. static void
  837. WriteTypeCheckArg(file, arg)
  838.     FILE *file;
  839.     register argument_t *arg;
  840. {
  841.     if (akCheck(arg->argKind, akbRequest)) {
  842.     WriteTypeCheck(file, arg);
  843.  
  844.     if (akCheck(arg->argKind, akbVariable))
  845.         WriteCheckMsgSize(file, arg);
  846.     }
  847. }
  848.  
  849. WriteAdjustRequestMsgPtr(file, arg)
  850.     FILE *file;
  851.     register argument_t *arg;
  852. {
  853.     register ipc_type_t *ptype = arg->argType;
  854.  
  855.     fprintf(file,
  856.     "\tIn%dP = (Request *) ((char *) In%dP + msgh_size_delta - %d);\n\n",
  857.     arg->argRequestPos+1, arg->argRequestPos,
  858.     ptype->itTypeSize + ptype->itPadSize);
  859. }
  860.  
  861. WriteTypeCheckRequestArgs(file, rt)
  862.     FILE *file;
  863.     register routine_t *rt;
  864. {
  865.     register argument_t *arg;
  866.     register argument_t *lastVarArg;
  867.  
  868.     lastVarArg = argNULL;
  869.     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
  870.  
  871.     /*
  872.      * Advance message pointer if the last request argument was
  873.      * variable-length and the request position will change.
  874.      */
  875.     if (lastVarArg != argNULL &&
  876.         lastVarArg->argRequestPos < arg->argRequestPos)
  877.     {
  878.         WriteAdjustRequestMsgPtr(file, lastVarArg);
  879.         lastVarArg = argNULL;
  880.     }
  881.  
  882.     /*
  883.      * Type-check the argument.
  884.      */
  885.     WriteTypeCheckArg(file, arg);
  886.  
  887.     /*
  888.      * Remember whether this was variable-length.
  889.      */
  890.     if (akCheckAll(arg->argKind, akbVariable|akbRequest))
  891.         lastVarArg = arg;
  892.     }
  893. }
  894.  
  895. static void
  896. WriteExtractArg(file, arg)
  897.     FILE *file;
  898.     register argument_t *arg;
  899. {
  900.     if (akCheckAll(arg->argKind, akbSendRcv|akbVarNeeded))
  901.     WriteExtractArgValue(file, arg);
  902.  
  903.     if ((akIdent(arg->argKind) == akeCount) &&
  904.     akCheck(arg->argKind, akbReturnSnd))
  905.     {
  906.     register ipc_type_t *ptype = arg->argParent->argType;
  907.  
  908.     if (ptype->itInLine && ptype->itVarArray)
  909.         WriteInitializeCount(file, arg);
  910.     }
  911.  
  912.     if (akCheckAll(arg->argKind, akbReturnSnd|akbPointer))
  913.     WriteInitializePtr(file, arg);
  914. }
  915.  
  916. static void
  917. WriteServerCallArg(file, arg)
  918.     FILE *file;
  919.     register argument_t *arg;
  920. {
  921.     ipc_type_t *it = arg->argType;
  922.     boolean_t NeedClose = FALSE;
  923.  
  924.     if (arg->argByReferenceServer)
  925.     fprintf(file, "&");
  926.  
  927.     if ((it->itInTrans != strNULL) &&
  928.     akCheck(arg->argKind, akbSendRcv) &&
  929.     !akCheck(arg->argKind, akbVarNeeded))
  930.     {
  931.     fprintf(file, "%s(", it->itInTrans);
  932.     NeedClose = TRUE;
  933.     }
  934.  
  935.     if (akCheck(arg->argKind, akbPointer))
  936.     fprintf(file, "%sP", arg->argVarName);
  937.     else if (akCheck(arg->argKind, akbVarNeeded))
  938.     fprintf(file, "%s", arg->argVarName);
  939.     else if (akCheck(arg->argKind, akbSendRcv)) {
  940.     if (akCheck(arg->argKind, akbIndefinite)) {
  941.         fprintf(file, "(In%dP->%s%s.msgt_inline) ",
  942.             arg->argRequestPos,
  943.             arg->argTTName,
  944.             arg->argLongForm ? ".msgtl_header" : "");
  945.         fprintf(file, "? %s ", InArgMsgField(arg));
  946.         fprintf(file, ": *((%s **)%s)",
  947.             FetchServerType(arg->argType->itElement),
  948.             InArgMsgField(arg));
  949.     }
  950.     else
  951.         fprintf(file, "%s", InArgMsgField(arg));
  952.     }
  953.     else
  954.     fprintf(file, "OutP->%s", arg->argMsgField);
  955.  
  956.     if (NeedClose)
  957.     fprintf(file, ")");
  958.  
  959.     if (!arg->argByReferenceServer && (arg->argMultiplier > 1))
  960.     fprintf(file, " / %d", arg->argMultiplier);
  961. }
  962.  
  963. static void
  964. WriteDestroyArg(file, arg)
  965.     FILE *file;
  966.     register argument_t *arg;
  967. {
  968.     register ipc_type_t *it = arg->argType;
  969.  
  970.     if (akCheck(arg->argKind, akbIndefinite)) {
  971.     /*
  972.      * Deallocate only if out-of-line.
  973.      */
  974.     argument_t *count = arg->argCount;
  975.     ipc_type_t *btype = it->itElement;
  976.     int    multiplier = btype->itTypeSize / btype->itNumber;
  977.  
  978.     fprintf(file, "\tif (!In%dP->%s%s.msgt_inline)\n",
  979.         arg->argRequestPos,
  980.         arg->argTTName,
  981.         arg->argLongForm ? ".msgtl_header" : "");
  982.     fprintf(file, "\t\tmig_deallocate(* (vm_offset_t **) %s, ",
  983.         InArgMsgField(arg));
  984.     if (multiplier > 1)
  985.         fprintf(file, "%d * ", multiplier);
  986.     fprintf(file, " %s);\n", InArgMsgField(count));
  987.     } else {
  988.     if (akCheck(arg->argKind, akbVarNeeded))
  989.         fprintf(file, "\t%s(%s);\n", it->itDestructor, arg->argVarName);
  990.     else
  991.         fprintf(file, "\t%s(%s);\n", it->itDestructor,
  992.         InArgMsgField(arg));
  993.     }
  994. }
  995.  
  996. static void
  997. WriteDestroyPortArg(file, arg)
  998.     FILE *file;
  999.     register argument_t *arg;
  1000. {
  1001.     register ipc_type_t *it = arg->argType;
  1002.  
  1003.     /*
  1004.      *    If a translated port argument occurs in the body of a request
  1005.      *    message, and the message is successfully processed, then the
  1006.      *    port right should be deallocated.  However, the called function
  1007.      *    didn't see the port right; it saw the translation.  So we have
  1008.      *    to release the port right for it.
  1009.      */
  1010.  
  1011.     if ((it->itInTrans != strNULL) &&
  1012.     (it->itOutName == MACH_MSG_TYPE_PORT_SEND))
  1013.     {
  1014.     fprintf(file, "\n");
  1015.     fprintf(file, "\tif (IP_VALID(%s))\n", InArgMsgField(arg));
  1016.     fprintf(file, "\t\tipc_port_release_send(%s);\n", InArgMsgField(arg));
  1017.     }
  1018. }
  1019.  
  1020. /*
  1021.  * Check whether WriteDestroyPortArg would generate any code for arg.
  1022.  */
  1023. boolean_t
  1024. CheckDestroyPortArg(arg)
  1025.     register argument_t *arg;
  1026. {
  1027.     register ipc_type_t *it = arg->argType;
  1028.  
  1029.     if ((it->itInTrans != strNULL) &&
  1030.     (it->itOutName == MACH_MSG_TYPE_PORT_SEND))
  1031.     {
  1032.     return TRUE;
  1033.     }
  1034.     return FALSE;
  1035. }
  1036.  
  1037. static void
  1038. WriteServerCall(file, rt)
  1039.     FILE *file;
  1040.     routine_t *rt;
  1041. {
  1042.     boolean_t NeedClose = FALSE;
  1043.  
  1044.     fprintf(file, "\t");
  1045.     if (rt->rtServerReturn != argNULL)
  1046.     {
  1047.     argument_t *arg = rt->rtServerReturn;
  1048.     ipc_type_t *it = arg->argType;
  1049.  
  1050.     fprintf(file, "OutP->%s = ", arg->argMsgField);
  1051.     if (it->itOutTrans != strNULL)
  1052.     {
  1053.         fprintf(file, "%s(", it->itOutTrans);
  1054.         NeedClose = TRUE;
  1055.     }
  1056.     }
  1057.     fprintf(file, "%s(", rt->rtServerName);
  1058.     WriteList(file, rt->rtArgs, WriteServerCallArg, akbServerArg, ", ", "");
  1059.     if (NeedClose)
  1060.     fprintf(file, ")");
  1061.     fprintf(file, ");\n");
  1062. }
  1063.  
  1064. static void
  1065. WriteGetReturnValue(file, rt)
  1066.     FILE *file;
  1067.     register routine_t *rt;
  1068. {
  1069.     if (rt->rtServerReturn != rt->rtRetCode)
  1070.     fprintf(file, "\tOutP->%s = KERN_SUCCESS;\n",
  1071.         rt->rtRetCode->argMsgField);
  1072. }
  1073.  
  1074. static void
  1075. WriteCheckReturnValue(file, rt)
  1076.     FILE *file;
  1077.     register routine_t *rt;
  1078. {
  1079.     if (rt->rtServerReturn == rt->rtRetCode)
  1080.     {
  1081.     fprintf(file, "\tif (OutP->%s != KERN_SUCCESS)\n",
  1082.         rt->rtRetCode->argMsgField);
  1083.     fprintf(file, "\t\treturn;\n");
  1084.     }
  1085. }
  1086.  
  1087. static void
  1088. WritePackArgType(file, arg)
  1089.     FILE *file;
  1090.     register argument_t *arg;
  1091. {
  1092.     fprintf(file, "\n");
  1093.  
  1094.     WritePackMsgType(file, arg->argType,
  1095.              arg->argType->itIndefinite ? d_NO : arg->argDeallocate,
  1096.              arg->argLongForm, !IsKernelServer,
  1097.              "OutP->%s", "%s", arg->argTTName);
  1098. }
  1099.  
  1100. static void
  1101. WritePackArgValue(file, arg)
  1102.     FILE *file;
  1103.     register argument_t *arg;
  1104. {
  1105.     register ipc_type_t *it = arg->argType;
  1106.  
  1107.     fprintf(file, "\n");
  1108.  
  1109.     if (it->itInLine && it->itVarArray) {
  1110.  
  1111.     if (it->itString) {
  1112.         /*
  1113.          *    Copy variable-size C string with mig_strncpy.
  1114.          *    Save the string length (+ 1 for trailing 0)
  1115.          *    in the argument`s count field.
  1116.          */
  1117.         fprintf(file,
  1118.         "\tOutP->%s = mig_strncpy(OutP->%s, %s, %d);\n",
  1119.         arg->argCount->argMsgField,
  1120.         arg->argMsgField,
  1121.         arg->argVarName,
  1122.         it->itNumber);
  1123.     }
  1124.     else {
  1125.         register argument_t *count = arg->argCount;
  1126.         register ipc_type_t *btype = it->itElement;
  1127.  
  1128.         /* Note btype->itNumber == count->argMultiplier */
  1129.  
  1130.         if (it->itIndefinite) {
  1131.         /*
  1132.          * If we are packing argument, it must be from
  1133.          * a local variable.
  1134.          */
  1135.         fprintf(file, "\tif (%sP != %s) {\n",
  1136.             arg->argVarName,
  1137.             arg->argVarName);
  1138.         fprintf(file, "\t\tOutP->%s%s.msgt_inline = FALSE;\n",
  1139.             arg->argTTName,
  1140.             arg->argLongForm ? ".msgtl_header" : "");
  1141.         if (arg->argDeallocate == d_YES)
  1142.             fprintf(file, "\t\tOutP->%s%s.msgt_deallocate = TRUE;\n",
  1143.                 arg->argTTName,
  1144.                 arg->argLongForm ? ".msgtl_header" : "");
  1145.         else if (arg->argDeallocate == d_MAYBE)
  1146.             fprintf(file, "\t\tOutP->%s%s.msgt_deallocate = %s;\n",
  1147.                 arg->argTTName,
  1148.                 arg->argLongForm ? ".msgtl_header" : "",
  1149.                 arg->argDealloc->argVarName);
  1150.         fprintf(file, "\t\t*((%s **)OutP->%s) = %sP;\n",
  1151.             FetchServerType(btype),
  1152.             arg->argMsgField,
  1153.             arg->argVarName);
  1154.         if (!arg->argRoutine->rtSimpleFixedReply)
  1155.             fprintf(file, "\t\tmsgh_simple = FALSE;\n");
  1156.         fprintf(file, "\t}\n\telse {\n\t");
  1157.         }
  1158.         fprintf(file, "\tbcopy((char *) %s, (char *) OutP->%s, ",
  1159.         arg->argVarName, arg->argMsgField);
  1160.         if (btype->itTypeSize > 1)
  1161.         fprintf(file, "%d * ",
  1162.             btype->itTypeSize);
  1163.         fprintf(file, "%s);\n",
  1164.         count->argVarName);
  1165.         if (it->itIndefinite)
  1166.         fprintf(file, "\t}\n");
  1167.     }
  1168.     }
  1169.     else if (arg->argMultiplier > 1)
  1170.     WriteCopyType(file, it, "OutP->%s", "/* %s */ %d * %s",
  1171.               arg->argMsgField,
  1172.               arg->argMultiplier,
  1173.               arg->argVarName);
  1174.     else if (it->itOutTrans != strNULL)
  1175.     WriteCopyType(file, it, "OutP->%s", "/* %s */ %s(%s)",
  1176.               arg->argMsgField, it->itOutTrans, arg->argVarName);
  1177.     else
  1178.     WriteCopyType(file, it, "OutP->%s", "/* %s */ %s",
  1179.               arg->argMsgField, arg->argVarName);
  1180. }
  1181.  
  1182. static void
  1183. WriteCopyArgValue(file, arg)
  1184.     FILE *file;
  1185.     argument_t *arg;
  1186. {
  1187.     fprintf(file, "\n");
  1188.     WriteCopyType(file, arg->argType, "/* %d */ OutP->%s", "In%dP->%s",
  1189.           arg->argRequestPos, arg->argMsgField);
  1190. }
  1191.  
  1192. static void
  1193. WriteAdjustMsgSimple(file, arg)
  1194.     FILE *file;
  1195.     register argument_t *arg;
  1196. {
  1197.     /* akbVarNeeded must be on */
  1198.  
  1199.     if (!arg->argRoutine->rtSimpleFixedReply)
  1200.     {
  1201.     fprintf(file, "\n");
  1202.     fprintf(file, "\tif (MACH_MSG_TYPE_PORT_ANY(%s))\n", arg->argVarName);
  1203.     fprintf(file, "\t\tmsgh_simple = FALSE;\n");
  1204.     }
  1205. }
  1206.  
  1207. static void
  1208. WriteAdjustMsgCircular(file, arg)
  1209.     FILE *file;
  1210.     register argument_t *arg;
  1211. {
  1212.     fprintf(file, "\n");
  1213.  
  1214.     if (arg->argType->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
  1215.     fprintf(file, "\tif (%s == MACH_MSG_TYPE_PORT_RECEIVE)\n",
  1216.         arg->argPoly->argVarName);
  1217.  
  1218.     /*
  1219.      *    The carried port right can be accessed in OutP->XXXX.  Normally
  1220.      *    the server function stuffs it directly there.  If it is InOut,
  1221.      *    then it has already been copied into the reply message.
  1222.      *    If the server function deposited it into a variable (perhaps
  1223.      *    because the reply message is variable-sized) then it has already
  1224.      *    been copied into the reply message.  Note we must use InHeadP
  1225.      *    (or In0P->Head) and OutHeadP to access the message headers,
  1226.      *    because of the variable-sized messages.
  1227.      */
  1228.  
  1229.     fprintf(file, "\tif (IP_VALID((ipc_port_t) InHeadP->msgh_reply_port) &&\n");
  1230.     fprintf(file, "\t    IP_VALID((ipc_port_t) OutP->%s) &&\n", arg->argMsgField);
  1231.     fprintf(file, "\t    ipc_port_check_circularity((ipc_port_t) OutP->%s, (ipc_port_t) InHeadP->msgh_reply_port))\n", arg->argMsgField);
  1232.     fprintf(file, "\t\tOutHeadP->msgh_bits |= MACH_MSGH_BITS_CIRCULAR;\n");
  1233. }
  1234.  
  1235. /*
  1236.  * Calculate the size of a variable-length message field.
  1237.  */
  1238. static void
  1239. WriteArgSize(file, arg)
  1240.     FILE *file;
  1241.     register argument_t *arg;
  1242. {
  1243.     register ipc_type_t *ptype = arg->argType;
  1244.     register int bsize = ptype->itElement->itTypeSize;
  1245.     register argument_t *count = arg->argCount;
  1246.  
  1247.     if (ptype->itIndefinite) {
  1248.     /*
  1249.      * Check descriptor.  If out-of-line, use standard size.
  1250.      */
  1251.     fprintf(file, "(OutP->%s%s.msgt_inline) ? ",
  1252.         arg->argTTName,
  1253.         arg->argLongForm ? ".msgtl_header" : "");
  1254.     }
  1255.  
  1256.     if (bsize > 1)
  1257.     fprintf(file, "%d * ", bsize);
  1258.     if (ptype->itString)
  1259.     /* get count from descriptor in message */
  1260.     fprintf(file, "OutP->%s", count->argMsgField);
  1261.     else
  1262.     /* get count from argument */
  1263.     fprintf(file, "%s", count->argVarName);
  1264.  
  1265.     /*
  1266.      * If the base type size is not a multiple of sizeof(int) [4],
  1267.      * we have to round up.
  1268.      */
  1269.     if (bsize % 4 != 0)
  1270.     fprintf(file, " + 3 & ~3");
  1271.  
  1272.     if (ptype->itIndefinite) {
  1273.     fprintf(file, " : sizeof(%s *)",
  1274.         FetchServerType(ptype->itElement));
  1275.     }
  1276. }
  1277.  
  1278. /*
  1279.  * Adjust message size and advance reply pointer.
  1280.  * Called after packing a variable-length argument that
  1281.  * has more arguments following.
  1282.  */
  1283. static void
  1284. WriteAdjustMsgSize(file, arg)
  1285.     FILE *file;
  1286.     register argument_t *arg;
  1287. {
  1288.     register routine_t *rt = arg->argRoutine;
  1289.     register ipc_type_t *ptype = arg->argType;
  1290.  
  1291.     /* There are more Out arguments.  We need to adjust msgh_size
  1292.        and advance OutP, so we save the size of the current field
  1293.        in msgh_size_delta. */
  1294.  
  1295.     fprintf(file, "\tmsgh_size_delta = ");
  1296.     WriteArgSize(file, arg);
  1297.     fprintf(file, ";\n");
  1298.  
  1299.     if (rt->rtNumReplyVar == 1)
  1300.     /* We can still address the message header directly.  Fill
  1301.        in the size field. */
  1302.  
  1303.     fprintf(file, "\tOutP->Head.msgh_size = %d + msgh_size_delta;\n",
  1304.             rt->rtReplySize);
  1305.     else
  1306.     if (arg->argReplyPos == 0)
  1307.     /* First variable-length argument.  The previous msgh_size value
  1308.        is the minimum reply size. */
  1309.  
  1310.     fprintf(file, "\tmsgh_size = %d + msgh_size_delta;\n",
  1311.         rt->rtReplySize);
  1312.     else
  1313.     fprintf(file, "\tmsgh_size += msgh_size_delta;\n");
  1314.  
  1315.     fprintf(file,
  1316.     "\tOutP = (Reply *) ((char *) OutP + msgh_size_delta - %d);\n",
  1317.     ptype->itTypeSize + ptype->itPadSize);
  1318. }
  1319.  
  1320. /*
  1321.  * Calculate the size of the message.  Called after the
  1322.  * last argument has been packed.
  1323.  */
  1324. static void
  1325. WriteFinishMsgSize(file, arg)
  1326.     FILE *file;
  1327.     register argument_t *arg;
  1328. {
  1329.     /* No more Out arguments.  If this is the only variable Out
  1330.        argument, we can assign to msgh_size directly. */
  1331.  
  1332.     if (arg->argReplyPos == 0) {
  1333.     fprintf(file, "\tOutP->Head.msgh_size = %d + (",
  1334.             arg->argRoutine->rtReplySize);
  1335.     WriteArgSize(file, arg);
  1336.     fprintf(file, ");\n");
  1337.     }
  1338.     else {
  1339.     fprintf(file, "\tmsgh_size += ");
  1340.     WriteArgSize(file, arg);
  1341.     fprintf(file, ";\n");
  1342.     }
  1343. }
  1344.  
  1345. static void
  1346. WritePackArg(file, arg)
  1347.     FILE *file;
  1348.     argument_t *arg;
  1349. {
  1350.     if (akCheck(arg->argKind, akbReplyInit))
  1351.     WritePackArgType(file, arg);
  1352.  
  1353.     if ((akIdent(arg->argKind) == akePoly) &&
  1354.     akCheck(arg->argKind, akbReturnSnd))
  1355.     WriteAdjustMsgSimple(file, arg);
  1356.  
  1357.     if (akCheckAll(arg->argKind, akbReturnSnd|akbVarNeeded))
  1358.     WritePackArgValue(file, arg);
  1359.     else if (akCheckAll(arg->argKind, akbReturnSnd|akbVariable)) {
  1360.     register ipc_type_t *it = arg->argType;
  1361.  
  1362.     if (it->itString) {
  1363.         /* Need to call strlen to calculate the size of the argument. */
  1364.         fprintf(file, "\tOutP->%s = strlen(OutP->%s) + 1;\n",
  1365.             arg->argCount->argMsgField, arg->argMsgField);
  1366.     } else if (it->itIndefinite) {
  1367.         /*
  1368.          * We know that array is in reply message.
  1369.          */
  1370.         fprintf(file, "\tif (%sP != OutP->%s) {\n",
  1371.             arg->argVarName,
  1372.             arg->argMsgField);
  1373.         fprintf(file, "\t\tOutP->%s%s.msgt_inline = FALSE;\n",
  1374.             arg->argTTName,
  1375.             arg->argLongForm ? ".msgtl_header" : "");
  1376.         if (arg->argDeallocate == d_YES)
  1377.         fprintf(file, "\t\tOutP->%s%s.msgt_deallocate = TRUE;\n",
  1378.             arg->argTTName,
  1379.             arg->argLongForm ? ".msgtl_header" : "");
  1380.         else if (arg->argDeallocate == d_MAYBE)
  1381.         fprintf(file, "\t\tOutP->%s%s.msgt_deallocate = %s;\n",
  1382.             arg->argTTName,
  1383.             arg->argLongForm ? ".msgtl_header" : "",
  1384.             arg->argDealloc->argVarName);
  1385.         fprintf(file, "\t\t*((%s **)OutP->%s) = %sP;\n",
  1386.             FetchServerType(it->itElement),
  1387.             arg->argMsgField,
  1388.             arg->argVarName);
  1389.         if (!arg->argRoutine->rtSimpleFixedReply)
  1390.         fprintf(file, "\t\tmsgh_simple = FALSE;\n");
  1391.         fprintf(file, "\t}\n");
  1392.     }
  1393.     }
  1394.  
  1395.     if (akCheck(arg->argKind, akbReplyCopy))
  1396.     WriteCopyArgValue(file, arg);
  1397.  
  1398.     /*
  1399.      *    If this is a KernelServer, and the reply message contains
  1400.      *    a receive right, we must check for the possibility of a
  1401.      *    port/message circularity.  If queueing the reply message
  1402.      *    would cause a circularity, we mark the reply message
  1403.      *    with the circular bit.
  1404.      */
  1405.  
  1406.     if (IsKernelServer &&
  1407.     akCheck(arg->argKind, akbReturnSnd) &&
  1408.     ((arg->argType->itOutName == MACH_MSG_TYPE_PORT_RECEIVE) ||
  1409.      (arg->argType->itOutName == MACH_MSG_TYPE_POLYMORPHIC)))
  1410.     WriteAdjustMsgCircular(file, arg);
  1411. }
  1412.  
  1413. /*
  1414.  * Handle reply arguments - fill in message types and copy arguments
  1415.  * that need to be copied.
  1416.  */
  1417. WritePackReplyArgs(file, rt)
  1418.     FILE *file;
  1419.     register routine_t *rt;
  1420. {
  1421.     register argument_t *arg;
  1422.     register argument_t *lastVarArg;
  1423.  
  1424.     lastVarArg = argNULL;
  1425.     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
  1426.  
  1427.     /*
  1428.      * Adjust message size and advance message pointer if
  1429.      * the last reply argument was variable-length and the
  1430.      * request position will change.
  1431.      */
  1432.     if (lastVarArg != argNULL &&
  1433.         lastVarArg->argReplyPos < arg->argReplyPos)
  1434.     {
  1435.         WriteAdjustMsgSize(file, lastVarArg);
  1436.         lastVarArg = argNULL;
  1437.     }
  1438.  
  1439.     /*
  1440.      * Copy the argument
  1441.      */
  1442.     WritePackArg(file, arg);
  1443.  
  1444.     /*
  1445.      * Remember whether this was variable-length.
  1446.      */
  1447.     if (akCheckAll(arg->argKind, akbReturnSnd|akbVariable))
  1448.         lastVarArg = arg;
  1449.     }
  1450.  
  1451.     /*
  1452.      * Finish the message size.
  1453.      */
  1454.     if (lastVarArg != argNULL)
  1455.     WriteFinishMsgSize(file, lastVarArg);
  1456. }
  1457.  
  1458. static void
  1459. WriteFieldDecl(file, arg)
  1460.     FILE *file;
  1461.     argument_t *arg;
  1462. {
  1463.     WriteFieldDeclPrim(file, arg, FetchServerType);
  1464. }
  1465.  
  1466. static void
  1467. WriteRoutine(file, rt)
  1468.     FILE *file;
  1469.     register routine_t *rt;
  1470. {
  1471.     fprintf(file, "\n");
  1472.  
  1473.     fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
  1474.     fprintf(file, "mig_internal novalue _X%s\n", rt->rtName);
  1475.     fprintf(file, "#if\t%s\n", NewCDecl);
  1476.     fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
  1477.     fprintf(file, "#else\n");
  1478.     fprintf(file, "\t(InHeadP, OutHeadP)\n");
  1479.     fprintf(file, "\tmach_msg_header_t *InHeadP, *OutHeadP;\n");
  1480.     fprintf(file, "#endif\n");
  1481.  
  1482.     fprintf(file, "{\n");
  1483.     WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request");
  1484.     WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply");
  1485.  
  1486.     WriteVarDecls(file, rt);
  1487.  
  1488.     WriteList(file, rt->rtArgs, WriteCheckDecl, akbRequestQC, "\n", "\n");
  1489.     WriteList(file, rt->rtArgs,
  1490.           IsKernelServer ? WriteTypeDeclOut : WriteTypeDeclIn,
  1491.           akbReplyInit, "\n", "\n");
  1492.  
  1493.     WriteList(file, rt->rtArgs, WriteLocalVarDecl,
  1494.           akbVarNeeded, ";\n", ";\n\n");
  1495.     WriteList(file, rt->rtArgs, WriteLocalPtrDecl,
  1496.           akbPointer, ";\n", ";\n\n");
  1497.  
  1498.     WriteCheckHead(file, rt);
  1499.  
  1500.     WriteTypeCheckRequestArgs(file, rt);
  1501.     WriteList(file, rt->rtArgs, WriteExtractArg, akbNone, "", "");
  1502.  
  1503.     WriteServerCall(file, rt);
  1504.     WriteGetReturnValue(file, rt);
  1505.  
  1506.     WriteReverseList(file, rt->rtArgs, WriteDestroyArg, akbDestroy, "", "");
  1507.  
  1508.     /*
  1509.      * For one-way routines, it doesn`t make sense to check the return
  1510.      * code, because we return immediately afterwards.  However,
  1511.      * kernel servers may want to deallocate port arguments - and the
  1512.      * deallocation must not be done if the return code is not KERN_SUCCESS.
  1513.      */
  1514.     if (rt->rtOneWay || rt->rtNoReplyArgs)
  1515.     {
  1516.     if (IsKernelServer)
  1517.     {
  1518.         if (rtCheckMaskFunction(rt->rtArgs, akbSendBody|akbSendRcv,
  1519.                 CheckDestroyPortArg))
  1520.         {
  1521.         WriteCheckReturnValue(file, rt);
  1522.         }
  1523.         WriteReverseList(file, rt->rtArgs, WriteDestroyPortArg,
  1524.              akbSendBody|akbSendRcv, "", "");
  1525.     }
  1526.     }
  1527.     else
  1528.     {
  1529.     WriteCheckReturnValue(file, rt);
  1530.  
  1531.     if (IsKernelServer)
  1532.         WriteReverseList(file, rt->rtArgs, WriteDestroyPortArg,
  1533.              akbSendBody|akbSendRcv, "", "");
  1534.  
  1535.     WriteReplyInit(file, rt);
  1536.     WritePackReplyArgs(file, rt);
  1537.     WriteReplyHead(file, rt);
  1538.     }
  1539.  
  1540.     fprintf(file, "}\n");
  1541. }
  1542.  
  1543. static void
  1544. WriteStubArgDecl(file, arg)
  1545.     FILE *file;
  1546.     argument_t *arg;
  1547. {
  1548.     char *ref = arg->argByReferenceServer ? "*" : "";
  1549.  
  1550.     fprintf(file, "\t%s %s%s", arg->argType->itServerType,
  1551.         ref, arg->argVarName);
  1552. }
  1553.  
  1554. static void
  1555. WriteStubDecl(file, rt)
  1556.     FILE *file;
  1557.     register routine_t *rt;
  1558. {
  1559.     fprintf(file, "\n");
  1560.     fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
  1561.     fprintf(file, "%s %s\n", ServerSideType(rt), rt->rtServerName);
  1562.     fprintf(file, "#if\t%s\n", NewCDecl);
  1563.     fprintf(file, "(\n");
  1564.     WriteList(file, rt->rtArgs, WriteStubArgDecl,
  1565.           akbServerArg, ",\n", "\n");
  1566.     fprintf(file, ")\n");
  1567.     fprintf(file, "#else\n");
  1568.     fprintf(file, "\t(");
  1569.     WriteList(file, rt->rtArgs, WriteNameDecl, akbServerArg, ", ", "");
  1570.     fprintf(file, ")\n");
  1571.     WriteList(file, rt->rtArgs, WriteStubArgDecl,
  1572.           akbServerArg, ";\n", ";\n");
  1573.     fprintf(file, "#endif\n");
  1574.     fprintf(file, "{\n");
  1575. }
  1576.  
  1577. void
  1578. WriteServer(file, stats)
  1579.     FILE *file;
  1580.     statement_t *stats;
  1581. {
  1582.     register statement_t *stat;
  1583.  
  1584.     WriteProlog(file);
  1585.     for (stat = stats; stat != stNULL; stat = stat->stNext)
  1586.     switch (stat->stKind)
  1587.     {
  1588.       case skRoutine:
  1589.         WriteRoutine(file, stat->stRoutine);
  1590.         break;
  1591.       case skImport:
  1592.       case skSImport:
  1593.         WriteImport(file, stat->stFileName);
  1594.         break;
  1595.       case skUImport:
  1596.         break;
  1597.       default:
  1598.         fatal("WriteServer(): bad statement_kind_t (%d)",
  1599.           (int) stat->stKind);
  1600.     }
  1601.     WriteEpilog(file, stats);
  1602. }
  1603.